home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mmdf / mmdf-IIb.43 / src / tools / checkup.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-02-28  |  30.5 KB  |  1,142 lines

  1. /*
  2.  *     MULTI-CHANNEL MEMO DISTRIBUTION FACILITY  (MMDF)
  3.  *
  4.  *
  5.  *     Copyright (C) 1979,1980,1981  University of Delaware
  6.  *
  7.  *     Department of Electrical Engineering
  8.  *     University of Delaware
  9.  *     Newark, Delaware  19711
  10.  *
  11.  *     Phone:  (302) 738-1163
  12.  *
  13.  *
  14.  *     This program module was developed as part of the University
  15.  *     of Delaware's Multi-Channel Memo Distribution Facility (MMDF).
  16.  *
  17.  *     Acquisition, use, and distribution of this module and its listings
  18.  *     are subject restricted to the terms of a license agreement.
  19.  *     Documents describing systems using this module must cite its source.
  20.  *
  21.  *     The above statements must be retained with all copies of this
  22.  *     program and may not be removed without the consent of the
  23.  *     University of Delaware.
  24.  *
  25.  *
  26.  *     version  -1    David H. Crocker    March   1979
  27.  *     version   0    David H. Crocker    April   1980
  28.  *     version  v7    David H. Crocker    May     1981
  29.  *     version   1    David H. Crocker    October 1981
  30.  *
  31.  */
  32. /*      check directory, file, and program conditions, for MMDF
  33.  *
  34.  *  Jan 82  D. Crocker    Cleaned up protection-setting, a bit more
  35.  *                        Temporarily ignore group id mismatches
  36.  *  Jun 82  S. Manion     Major functional upgrade, such as verifying
  37.  *                        necessary alias entries exist.
  38.  *  Feb 84  D. Long       Check for slave in cmddfldir...not /usr/mmdf/lib.
  39.  *  Mar 84  D. Long       Report the line type of dialports.
  40.  */
  41.  
  42. #include "util.h"
  43. #include "mmdf.h"
  44. #include <pwd.h>
  45. #include <sys/stat.h>
  46. #include "ch.h"
  47. #ifndef NODIAL
  48. #include "d_proto.h"
  49. #include "d_structs.h"
  50. #endif /* NODIAL */
  51. #include "gettys.h"
  52. #include "dm.h"
  53.  
  54. #define MAXARG 50
  55.  
  56. /*  maximum number of output lines to be queued at once  */
  57. #define         QUESIZ          20
  58.  
  59. /*  the maximum number of path names that can be remembered as
  60.  *  having been checked already.  See chkpath()
  61. */
  62. #define         MAXPATH         15
  63.  
  64. /*  various verbosity levels  */
  65. #define         PERROR             01   /*  perror() should be called */
  66. #define         ANYLEVEL          070   /*  any bit in this field */
  67. #define         LEVEL1            010   /*  fatal */
  68. #define         LEVEL1P      LEVEL1|PERROR
  69. #define         LEVEL3            020   /*  major section */
  70. #define         LEVEL4            030   /*  sub-section */
  71. #define         LEVEL5            040
  72. #define         LEVEL6            050
  73. #define         LEVEL6_5          060   /*  warning [..] messages */
  74. #define         LEVEL7            070   /* nitty gritty junk */
  75. #define         LEVEL0       LEVEL1|PERROR
  76.  
  77. #define         BACKGROUND      LEVEL6  /* default verbosity */
  78. #define         FINAL           0
  79. #define         PARTIAL         1
  80.  
  81. extern char *dupfpath();
  82. extern char *strncpy();
  83. extern int  sys_nerr;
  84. extern char *sys_errlist[];
  85. extern int  errno;
  86.  
  87. extern LLog msglog;
  88. extern Chan **ch_tbsrch;       /* defined channels */
  89. extern Table **tb_list;        /* full list of known tables */
  90.  
  91. extern Domain **dm_list;
  92. extern char *mmdflogin;        /* login name for mmdf processes */
  93. extern char *mmtailor;        /* external tailoring information */
  94.  
  95.  
  96. extern char     *lckdfldir,
  97.            *pn_quedir;
  98.  
  99. #ifdef JNTMAIL
  100. int daemonuid,
  101.     daemongid;
  102. #define DAEMON  "daemon";       /* Can be overridden at compile time */
  103. char daemonname[]  = DAEMON;
  104. #endif /* JNTMAIL */
  105.  
  106. extern char *locmachine, *locfullmachine, *locfullname, *locname, *locdomain;
  107.  
  108. extern char
  109.         *logdfldir,
  110.         *phsdfldir,
  111.         *tbldfldir,
  112.         *tbldbm,
  113.         *cmddfldir,
  114.         *chndfldir,
  115.         *mldfldir;
  116.  
  117. extern char
  118.         *quedfldir,
  119.         *tquedir,
  120.         *aquedir,
  121.         *mquedir,
  122.         *squepref;
  123.  
  124. extern char
  125.         *pathdeliver,
  126.         *pathsubmit,
  127.         *pathpkup,
  128.         *pathmail;
  129.  
  130. extern char *tai_eptr;
  131.  
  132. extern int queprot;             /* protection on quedfldir[] parent */
  133.  
  134. extern struct ll_struct    msglog,
  135.             chanlog;
  136.  
  137. #ifndef NODIAL
  138. extern struct ll_struct    ph_log;
  139. extern struct dialports *d_prts;
  140. extern struct directlines *d_lines;
  141. #endif /* NODIAL */
  142. extern struct passwd *getpwuid ();
  143. extern struct passwd *getpwnam ();
  144.  
  145. struct stat statbuf;
  146.  
  147. struct prtque  {
  148.     int q_level;
  149.     char q_text[126];
  150. };
  151.  
  152. int mmdfuid,
  153.     mmdfgid;
  154. int rootgid;
  155. int verbosity = BACKGROUND;
  156. char hdrfmt[] = "\n%-24s: %s\n";
  157. char subhdrfmt[] = "    %-20s: %s\n";
  158. char probfmt[] = "%-18s: %s\n";
  159. char errflg;                    /* error during mmdf_init */
  160. char *xerrstr();
  161. /* */
  162.  
  163. main (argc, argv)
  164.   int argc;
  165.   char *argv[];
  166. {
  167.     char tmpfile[FILNSIZE];
  168.     struct passwd *pwdptr;
  169.     int ind;
  170.  
  171.     /*  check for the verbosity flag  */
  172.     flaginit (argc, argv);
  173.  
  174.     que (BACKGROUND, "\n**  Asterisks indicate potentially serious anomolies.\n");
  175.     que (LEVEL6_5, "[ Information which is bracketed is advisory. ]\n");
  176.     qflush (LEVEL0);
  177.  
  178.     chktai ();  /* is the tailoring file there ? */
  179.  
  180.     mmdf_init (argv[0]);
  181.     if (errflg)
  182.     endit (NOTOK);
  183.     ll_hdinit (&msglog, argv[0]);
  184.     msglog.ll_file = dupfpath (msglog.ll_file, logdfldir);
  185.  
  186. #ifdef JNTMAIL
  187.     if ((pwdptr = getpwnam (daemonname)) == (struct passwd *) NULL)
  188.     {
  189.       que (LEVEL1, hdrfmt, "** No /etc/passwd login", daemonname);
  190.       endit (NOTOK);
  191.     }
  192.     daemonuid = pwdptr -> pw_uid;
  193.     daemongid = pwdptr -> pw_gid;
  194. #endif /* JNTMAIL */
  195.  
  196.     que (BACKGROUND, hdrfmt, "Default local machine name", locmachine);
  197.     que (LEVEL7, subhdrfmt, "", "this is your 'official' machine name");
  198.     qflush (LEVEL7);
  199.  
  200.     que (BACKGROUND, hdrfmt, "Default full local machine name", locfullmachine);
  201.     que (LEVEL7, subhdrfmt, "", "this is your 'official' full machine name");
  202.     qflush (LEVEL7);
  203.  
  204.     que (BACKGROUND, hdrfmt, "Default local name", locname);
  205.     que (LEVEL7, subhdrfmt, "", "this is your 'official' host name");
  206.     qflush (LEVEL7);
  207.  
  208.     que (BACKGROUND, hdrfmt, "Default full local name", locfullname);
  209.     que (LEVEL7, subhdrfmt, "", "this is your 'official' full domain name");
  210.     qflush (LEVEL7);
  211.  
  212.     que (BACKGROUND, hdrfmt, "Default domain name", locdomain);
  213.     que (LEVEL7, subhdrfmt, "", "this is your 'official' domain name");
  214.     qflush (LEVEL7);
  215.  
  216.     /*  get uid & gid for mmdf login, for setting directory ownerships */
  217.     if ((pwdptr = getpwnam (mmdflogin)) == (struct passwd *) NULL)
  218.     {
  219.     que (LEVEL1, hdrfmt, "** No /etc/passwd login", mmdflogin);
  220.     endit (NOTOK);
  221.     }
  222.     mmdfuid = pwdptr -> pw_uid;
  223.     mmdfgid = pwdptr -> pw_gid;
  224.  
  225.     que (LEVEL3, "\nMMDF login %-11s  : uid (%d), gid (%d)\n",
  226.         mmdflogin, mmdfuid, mmdfgid);
  227.     chkalias (mmdflogin);
  228.     que (LEVEL7, subhdrfmt, "", "alias this to root or systems staff");
  229.     qflush (LEVEL7);
  230.     qflush (LEVEL3);
  231.  
  232.     /* check for hashed table, if required */
  233.     if (tbldbm != (char *) 0)
  234.     {
  235.     que (BACKGROUND, hdrfmt, "MMDF DBM database", tbldbm);
  236.     que (LEVEL7, hdrfmt, "", "compiled by dbmbuild");
  237.     qflush (LEVEL7);
  238.  
  239.     getfpath (tbldbm, tbldfldir, tmpfile);
  240.     strcat (tmpfile, ".dir");
  241.     que (LEVEL7, subhdrfmt, "data directory", tmpfile);
  242.     chkfile (tmpfile, 0644, 0664, mmdfuid, mmdfgid, mmdflogin);
  243.  
  244.     getfpath (tbldbm, tbldfldir, tmpfile);
  245.     strcat (tmpfile, ".pag");
  246.     que (LEVEL7, subhdrfmt, "data pages", tmpfile);
  247.     chkfile (tmpfile, 0644, 0664, mmdfuid, mmdfgid, mmdflogin);
  248.     qflush (LEVEL7);
  249.     }
  250.  
  251.     que (BACKGROUND, hdrfmt, "Trouble report address", "Postmaster");
  252.     que (LEVEL7, subhdrfmt, "", "alias this to root or systems staff");
  253.     qflush (LEVEL7);
  254.     chkalias ("Postmaster");    /*  make sure the name is aliased  */
  255.     qflush (LEVEL0);
  256.  
  257.     if ((pwdptr = getpwuid (0)) != (struct passwd *) NULL)
  258.     rootgid = pwdptr -> pw_gid;
  259.  
  260.     que (LEVEL3, hdrfmt, "Checking directories", "");
  261.  
  262.     /*  standard directories */
  263.     que (LEVEL4, subhdrfmt, "Logging directory", logdfldir);
  264.     if (chkfile (logdfldir, 0711, 0755, mmdfuid, mmdfgid, mmdflogin) >= OK)
  265.     chklog ();
  266.     qflush (LEVEL4);
  267.  
  268.     que (LEVEL4, "\n");
  269.     que (LEVEL4, subhdrfmt, "Phase (timestamps)", phsdfldir);
  270.     chkfile (phsdfldir, 0711, 0755, mmdfuid, mmdfgid, mmdflogin);
  271.     qflush (LEVEL4);
  272.  
  273. #ifndef V4_2BSD
  274.     que (LEVEL4, "\n");
  275.     que (LEVEL4, subhdrfmt, "Locking directory", lckdfldir);
  276.     chkfile (lckdfldir, 0777, 0777, mmdfuid, mmdfgid, mmdflogin);
  277.     qflush (LEVEL4);
  278. #endif /* V4_2BSD */
  279.  
  280. #ifdef JNTMAIL
  281.     que (LEVEL4, "\n");
  282.     que (LEVEL4, subhdrfmt, "NIFTP spool directory", pn_quedir);
  283.     chkfile (pn_quedir, 0700, 0700, daemonuid, daemongid, daemonname);
  284.     qflush (LEVEL4);
  285. #endif
  286.  
  287.     que (LEVEL4, "\n");
  288.     que (LEVEL4, subhdrfmt, "Tables & scripts", tbldfldir);
  289.     if (chkfile (tbldfldir, 0711, 0755, mmdfuid, mmdfgid, mmdflogin) >= OK)
  290.     chktab ();
  291.     qflush (LEVEL4);
  292.  
  293.     que (LEVEL4, hdrfmt, "MMDF Commands", cmddfldir);
  294.     if (chkfile (cmddfldir, 0711, 0755, mmdfuid, mmdfgid, mmdflogin) >= OK)
  295.     chkcmd ();
  296.     qflush (LEVEL4);
  297.  
  298.     que (LEVEL4, hdrfmt, "Channel programs", chndfldir);
  299.     if (chkfile (chndfldir, 0500, 0770, mmdfuid, mmdfgid, mmdflogin) >= OK)
  300.     chkchan ();
  301.     qflush (LEVEL4);
  302.  
  303.     if (isstr(mldfldir))
  304.     {                           /* all mail delivered in common dir     */
  305.     que (LEVEL4, hdrfmt, "Shared receipt directory", mldfldir);
  306.     chkfile (mldfldir, 0777, 0777, mmdfuid, mmdfgid, mmdflogin);
  307.     qflush (LEVEL4);
  308.     }
  309.     qflush (LEVEL0);
  310.  
  311.     /*  queue directory substructure */
  312.     que (LEVEL4, hdrfmt, "Mail queue home", quedfldir);
  313.     if (chkpath (FINAL, quedfldir, 0777, 0777, mmdfuid, mmdfgid, mmdflogin) < OK)
  314.     que (LEVEL1, "cannot check queue further\n");
  315.     else
  316.     {
  317.     que (LEVEL7, "\t(changing into queue home directory...)\n");
  318.     if (chdir (quedfldir) < OK)
  319.     {
  320.         que (LEVEL1, probfmt, "cannot chdir", xerrstr());
  321.         que (LEVEL1, "unable to check queue directory tree further\n");
  322.     }
  323.     else
  324.     {
  325.         qflush (LEVEL7);
  326.         que (LEVEL5, subhdrfmt, "Queue lock", "home's parent directory");
  327.         if (stat ("..", &statbuf) < OK)
  328.         que (LEVEL1P, "cannot stat home queue parent, ");
  329.         else
  330.         {
  331.         statbuf.st_mode &= 06707;
  332.         if (statbuf.st_mode != queprot)
  333.             que (LEVEL1, "Wrong mode        : (0%o) should be (0%o)\n",
  334.                 statbuf.st_mode, queprot);
  335.         }
  336.         qflush (LEVEL5);
  337.  
  338.         que (LEVEL5, subhdrfmt, "Address-building", tquedir);
  339.         chkpath (FINAL, tquedir, 0777, 0777, mmdfuid, mmdfgid, mmdflogin);
  340.         qflush (LEVEL5);
  341.  
  342.         que (LEVEL5, subhdrfmt, "Queued addresses", aquedir);
  343.         chkpath (FINAL, aquedir, 0777, 0777, mmdfuid, mmdfgid, mmdflogin);
  344.         qflush (LEVEL5);
  345.  
  346.         que (LEVEL5, subhdrfmt, "Message text", mquedir);
  347.         chkpath (FINAL, mquedir, 0777, 0777, mmdfuid, mmdfgid, mmdflogin);
  348.         qflush (LEVEL5);
  349.  
  350.         que (LEVEL5, "Queueing directories:\n");
  351.         for (ind = 0; ch_tbsrch[ind] != (Chan *) 0; ind++)
  352.         {
  353.             static char path[64];
  354.  
  355.             (void) sprintf (path, "%s%s",
  356.             squepref, ch_tbsrch[ind] -> ch_queue);
  357.         que (LEVEL5, subhdrfmt, ch_tbsrch[ind] -> ch_show, path);
  358.         chkpath (FINAL, path, 0777, 0777, mmdfuid, mmdfgid, mmdflogin);
  359.         qflush (LEVEL5);
  360.         }
  361.     }
  362.     }
  363.     qflush (LEVEL0);
  364.  
  365. #ifndef NODIAL
  366.     que (LEVEL4, hdrfmt, "Dial out ports", "");
  367.     chk_dprts ();               /*  check the dial out ports  */
  368.     qflush (LEVEL0);
  369.  
  370.     que (LEVEL4, hdrfmt, "Direct-connect lines", "");
  371.     chk_dirlin ();              /*  check the direct lines  */
  372.     qflush (LEVEL0);
  373. #endif /* NODIAL */
  374.  
  375.     endit (OK);
  376. }
  377. /* */
  378.  
  379. flaginit (argc, argv)
  380. int argc;
  381. char *argv[];
  382. {
  383.     register int argind, charind;
  384.  
  385.     for (argind = 1;  argind < argc;  argind++)
  386.     if (argv[argind][0] == '-')
  387.         for (charind = 1;  argv[argind][charind] != '\0';  charind++)
  388.         switch (argv[argind][charind])
  389.         {
  390.             case 'p':           /* only note problems */
  391.             verbosity = LEVEL1;
  392.             break;
  393.  
  394.             case 'v':
  395.             verbosity = atoi (&argv[argind][++charind]);
  396.             if (verbosity < 0)
  397.                 verbosity = LEVEL1;
  398.             if (verbosity == 0)
  399.                 verbosity = LEVEL7;
  400.             while (isdigit (argv[argind][charind]))
  401.                 charind++;
  402.             charind--;
  403.             break;
  404.  
  405.             default:
  406.             printf ("Unknown flag %c\n", argv[argind][charind]);
  407.             printf ("Usage:  %s [-p][-v<verbosity>]\n", argv[0]);
  408.             exit (NOTOK);
  409.         }
  410. }
  411. /* */
  412.  
  413. #ifndef NODIAL
  414. chk_dprts ()
  415. {
  416.     struct ttys data;
  417.     char desc[30];
  418.     register int index, result;
  419.  
  420.     for (index = 0;  d_prts[index].p_port != NULL;  index++)
  421.     {
  422.     /*  check the dial out lines  */
  423.     (void) sprintf (desc, "0%o %.25s", d_prts[index].p_speed,
  424.         d_prts[index].p_ltype);
  425.     que (LEVEL5, subhdrfmt, d_prts[index].p_port, desc);
  426.     qflush (LEVEL5);
  427.  
  428.     /*  verify that the device exists  */
  429.     if (stat (d_prts[index].p_port, &statbuf) < 0)
  430.         que (LEVEL1, probfmt, "No port", xerrstr());
  431.     else
  432.         que (LEVEL7, "\tPort exists\n");
  433.     qflush (LEVEL7);
  434.  
  435.     /*  make sure it is not enabled  */
  436.     result = getttynam (&data, &d_prts[index].p_port[5]);
  437.     if (result == BADDATA)
  438.         que (LEVEL1, "No listing        : Port not in /etc/ttys\n");
  439.     else
  440.         if (data.t_valid == 0)
  441.         que (LEVEL7, "\tPort is set correctly (disabled)\n");
  442.         else
  443.         que (LEVEL1, "Wrong state      : Port should not be enabled\n");
  444.     qflush (LEVEL7);
  445.  
  446.     /*  make sure the lines dialer exists  */
  447.     if (stat (d_prts[index].p_acu, &statbuf) < 0)
  448.         que (LEVEL1P, "No dialer         : (%s)\n", d_prts[index].p_acu);
  449.     else
  450.         que (LEVEL7, "\tDialer (%s) exists\n", d_prts[index].p_acu);
  451.  
  452.     qflush (LEVEL5);
  453.     }
  454.     if (index == 0)
  455.     {
  456.     que (LEVEL5, subhdrfmt, "None", "");
  457.     qflush (LEVEL5);
  458.     }
  459. }
  460. /* */
  461.  
  462. chk_dirlin()
  463.     register int index, ret;
  464.     struct ttys ttybuf;
  465.  
  466.     for (index = 0;  d_lines[index].l_name != 0;  index++)
  467.     {
  468.     que (LEVEL5, subhdrfmt, d_lines[index].l_name, d_lines[index].l_tty);
  469.     qflush (LEVEL5);
  470.  
  471.     /*  verify that the device exists  */
  472.     if (stat (d_lines[index].l_tty, &statbuf) < 0)
  473.         que (LEVEL1, probfmt, "No line", xerrstr());
  474.     else
  475.         que (LEVEL7, "\tLine exists\n");
  476.     qflush (LEVEL7);
  477.  
  478.     /*  Is the line disabled?  */
  479.     ret = getttynam (&ttybuf, &d_lines[index].l_tty[5]);
  480.     if (ret == BADDATA)
  481.         que (LEVEL1, "No listing        : Line not in /etc/ttys\n");
  482.     else
  483.         if (ttybuf.t_valid == 0)
  484.         que (LEVEL7, "\tLine setup correctly (disabled)\n");
  485.         else
  486.         que (LEVEL1,
  487.             "Wrong state       : Line must NOT be enabled for terminal login\n");
  488.  
  489.     qflush (LEVEL5);
  490.     }
  491.     if (index == 0)
  492.     {
  493.     que (LEVEL5, subhdrfmt, "None", "");
  494.     qflush (LEVEL5);
  495.     }
  496. }
  497. #endif /* NODIAL */
  498. /* */
  499.  
  500. chklog ()
  501. {
  502.  
  503.     que (LEVEL7, "\n(changing into log directory...)\n");
  504.     qflush (LEVEL6);
  505.  
  506.     if (chdir (logdfldir) < OK)
  507.     {
  508.     que (LEVEL1, probfmt, "cannot chdir", xerrstr());
  509.     return;
  510.     }
  511.  
  512.     que (LEVEL6, subhdrfmt, "message-level log", msglog.ll_file);
  513.     chkfile (msglog.ll_file, 0622, 0666, mmdfuid, mmdfgid, mmdflogin);
  514.     qflush (LEVEL6);
  515.  
  516.     que (LEVEL6, subhdrfmt, "channel log", chanlog.ll_file);
  517.     chkfile (chanlog.ll_file, 0622, 0666, mmdfuid, mmdfgid, mmdflogin);
  518.     qflush (LEVEL6);
  519.  
  520. #ifndef NODIAL
  521.     que (LEVEL6, subhdrfmt, "phone (link) log", ph_log.ll_file);
  522.     chkfile (ph_log.ll_file, 0622, 0666, mmdfuid, mmdfgid, mmdflogin);
  523.     qflush (LEVEL6);
  524. #endif /* NODIAL */
  525. }
  526. /* */
  527.  
  528. chktab ()
  529. {
  530.     int didone;
  531.     register int ind, n;
  532.  
  533.     que (LEVEL7, "\n(changing into table directory...)\n");
  534.     qflush (LEVEL6);
  535.  
  536.     if (chdir (tbldfldir) < OK)
  537.     {
  538.     que (LEVEL1, probfmt, "cannot chdir", xerrstr());
  539.     return;
  540.     }
  541.  
  542.     que (LEVEL4, "\nChannel name tables & associated system entries:\n");
  543.     for (ind = 0; ch_tbsrch[ind] != (Chan *) 0; ind++)
  544.     {
  545.     if (ind > 0)
  546.         que (LEVEL5, "\n");
  547.     que (LEVEL5, subhdrfmt, ch_tbsrch[ind] -> ch_show,
  548.             ch_tbsrch[ind] -> ch_name);
  549.     que (LEVEL6, subhdrfmt, "Queue name", ch_tbsrch[ind] -> ch_queue);
  550.     qflush (LEVEL6);
  551.  
  552.     /*  verify that ch_name is legal, ie, less than 8 chars
  553.      *  long, and containing only alphanumerics or -.
  554.      */
  555.     for (n = 0;  ch_tbsrch[ind] -> ch_name[n] != '\0';  n++)
  556.         if( ((isalnum (ch_tbsrch[ind] -> ch_name[n]) == 0) &&
  557.          (ch_tbsrch[ind] -> ch_name[n] != '-'      )   ) ||
  558.         (n > 8                                          )   )
  559.         break;
  560.     /*  make sure the loop terminated normally  */
  561.     if (n > 8)
  562.         que (LEVEL1, "Long name         : '%s' should be 8 or fewer characters\n",
  563.             ch_tbsrch[ind] -> ch_name);
  564.     else
  565.         if (ch_tbsrch[ind] -> ch_name[n] != '\0')
  566.         que (LEVEL1, "Illegal char      : (%c) in '%s'\n",
  567.             ch_tbsrch[ind] -> ch_name[n], ch_tbsrch[ind] -> ch_name);
  568.  
  569.     que (LEVEL6, subhdrfmt, "  Local host name",
  570.                     ch_tbsrch[ind] -> ch_lname);
  571.     que (LEVEL6, subhdrfmt, "  Local domain name",
  572.                     ch_tbsrch[ind] -> ch_ldomain);
  573.     qflush (LEVEL6);
  574.  
  575.     cktable (ch_tbsrch[ind] -> ch_table, "Channel table");
  576.  
  577.     if (ch_tbsrch[ind] -> ch_indest != (Table *) 0)
  578.         cktable (ch_tbsrch[ind] -> ch_indest, "Destination filter");
  579.  
  580.     if (ch_tbsrch[ind] -> ch_outdest != (Table *) 0)
  581.         cktable (ch_tbsrch[ind] -> ch_outdest, "Destination filter");
  582.  
  583.     if (ch_tbsrch[ind] -> ch_insource != (Table *) 0)
  584.         cktable (ch_tbsrch[ind] -> ch_insource, "Source filter");
  585.  
  586.     if (ch_tbsrch[ind] -> ch_outsource != (Table *) 0)
  587.         cktable (ch_tbsrch[ind] -> ch_outsource, "Source filter");
  588.  
  589.     if (ch_tbsrch[ind] -> ch_known != (Table *) 0)
  590.         cktable (ch_tbsrch[ind] -> ch_known, "Table of known hosts");
  591.  
  592.     if (ch_tbsrch[ind] -> ch_script != 0)
  593.     {
  594.         que (LEVEL6, subhdrfmt, "Dialing script",
  595.                     ch_tbsrch[ind] -> ch_script);
  596.         if (stat (ch_tbsrch[ind] -> ch_script, &statbuf) < OK)
  597.         que (LEVEL1, probfmt, "cannot stat", xerrstr());
  598.         qflush (LEVEL6);
  599.     }
  600.  
  601.     if (ch_tbsrch[ind] -> ch_trans != (char *) DEFTRANS)
  602.     {
  603.         que (LEVEL6, subhdrfmt, "Phone transcript",
  604.                 ch_tbsrch[ind] -> ch_trans );
  605.         qflush (LEVEL6);
  606.     }
  607.     if (ch_tbsrch[ind] -> ch_login != NOLOGIN)
  608.         chklogin (ch_tbsrch[ind]);
  609.     qflush (LEVEL5);
  610.     }
  611.     qflush (LEVEL4);
  612.  
  613.     que (LEVEL4, hdrfmt, "Domain tables", "");
  614.     for (didone = FALSE, ind = 0; dm_list[ind] != (Domain *) 0; ind++)
  615.     {
  616.     if (dm_list[ind] -> dm_table -> tb_fp == (FILE *) NOTOK)
  617.         continue;
  618.     didone = TRUE;
  619.     que (LEVEL5, subhdrfmt,
  620.          isstr(dm_list[ind] -> dm_domain) ? dm_list[ind] -> dm_domain : "(root)",
  621.          dm_list[ind] -> dm_show);
  622.  
  623.     /*  verify that spec is legal, containing only alphanumerics or -.
  624.      */
  625.     for (n = 0;  dm_list[ind] -> dm_domain[n] != '\0';  n++)
  626.         if( ((isalnum (dm_list[ind] -> dm_domain[n]) == 0) &&
  627.          (dm_list[ind] -> dm_domain[n] != '-'      )  &&
  628.          (dm_list[ind] -> dm_domain[n] != '.'      )   ) )
  629.         break;
  630.  
  631.     /*  make sure the loop terminated normally  */
  632.     if (dm_list[ind] -> dm_domain[n] != '\0')
  633.         que (LEVEL1, "Illegal char      : (%c) in '%s'\n",
  634.         dm_list[ind] -> dm_domain[n], dm_list[ind] -> dm_domain);
  635.  
  636.     cktable(dm_list[ind] -> dm_table, "");
  637.     qflush (LEVEL5);
  638.     }
  639.     if (!didone)
  640.     {
  641.     que (LEVEL5, subhdrfmt, "None", "");
  642.     qflush (LEVEL5);
  643.     }
  644.  
  645.     que (LEVEL4, hdrfmt, "Additional tables", "");
  646.     for (didone = FALSE, ind = 0; tb_list[ind] != (Table *) 0; ind++)
  647.     {
  648.     if (tb_list[ind] -> tb_fp == (FILE *) NOTOK)
  649.         continue;           /* already done */
  650.  
  651.     didone = TRUE;
  652.     que (LEVEL5, subhdrfmt, tb_list[ind] -> tb_show,
  653.                 tb_list[ind] -> tb_name);
  654.  
  655.     /*  verify that spec is legal, ie, less than 8 chars
  656.      *  long, and containing only alphanumerics or -.
  657.      */
  658.     for (n = 0;  tb_list[ind] -> tb_name[n] != '\0';  n++)
  659.         if( ((isalnum (tb_list[ind] -> tb_name[n]) == 0) &&
  660.          (tb_list[ind] -> tb_name[n] != '-'      )   &&
  661.          (tb_list[ind] -> tb_name[n] != '.'      )   ) )
  662.         break;
  663.  
  664.     /*  make sure the loop terminated normally  */
  665.     if (tb_list[ind] -> tb_name[n] != '\0')
  666.         que (LEVEL1, "Illegal char      : (%c) in '%s'\n",
  667.         tb_list[ind] -> tb_name[n], tb_list[ind] -> tb_name);
  668.  
  669.         cktable (tb_list[ind], "");
  670.     qflush (LEVEL5);
  671.     }
  672.     if (!didone)
  673.     {
  674.     que (LEVEL5, subhdrfmt, "None", "");
  675.     qflush (LEVEL5);
  676.     }
  677.     qflush (LEVEL4);
  678. }
  679. /* */
  680.  
  681. cktable(tb, title)
  682. register Table *tb;
  683. register char *title;
  684. {
  685.     struct stat statbuf;
  686.  
  687.     tb -> tb_fp = (FILE *) NOTOK;    /* flag this table as processed */
  688.     if ((tb -> tb_flags&TB_SRC) == TB_NS) {
  689.     que (LEVEL6, subhdrfmt, title, "(via nameserver)");
  690.         return;
  691.     } else {
  692.     que (LEVEL6, subhdrfmt, title, tb -> tb_file);
  693.     if (stat (tb -> tb_file, &statbuf) < OK)
  694.         que (LEVEL1, probfmt, "cannot stat", xerrstr());
  695.     }
  696.     qflush (LEVEL6);
  697. }
  698.  
  699. chklogin (chanptr)
  700. Chan *chanptr;
  701. {
  702.     register char *name;
  703.     struct passwd *ret, *getpwnam ();
  704.     char slaveloc[FILNSIZE];
  705.     int mode;
  706.  
  707.     /*  transfer to a more accessable variable  */
  708.     name = chanptr -> ch_login;
  709.  
  710.     /*  verify that there is a login for this channel  */
  711.     ret = getpwnam (name);
  712.     if (ret == NULL)
  713.     {
  714.     que (LEVEL1, "No login          : for '%s'\n", name);
  715.     return;
  716.     }
  717.  
  718.     que (LEVEL6, subhdrfmt, "Login name", name);
  719.     chkalias (name);            /*  make sure the name is aliased  */
  720.     qflush (LEVEL6);
  721.  
  722.     /*  make sure the login program is the standard slave program  */
  723.     if ((initstr("pobox", chanptr -> ch_ppath, 5) != (-1)) &&
  724.     ((chanptr -> ch_access & DLVRPSV) != 0        )   )
  725.     {
  726.     strcat(strcpy(slaveloc,cmddfldir), "/slave");
  727.     if (strcmp (ret -> pw_shell, slaveloc) != 0)
  728.         que (LEVEL1, "Bad login prog    : '%s' is not phonenet slave\n",
  729.                 ret -> pw_shell);
  730.     else
  731.         que (LEVEL6, subhdrfmt, "Login program", ret -> pw_shell);
  732.     qflush (LEVEL6);
  733.     }
  734.     else
  735.     que (LEVEL6_5, "\t[ Login program : %s ]\n", ret -> pw_shell);
  736.     qflush (LEVEL6_5);
  737.  
  738.     /*  verify that the login directory exists and check protections  */
  739.     if (stat (ret -> pw_dir, &statbuf) < OK)
  740.     {
  741.     que (LEVEL1P, "Bad login dir     : Couldn't stat '%s'; ",
  742.             ret -> pw_dir);
  743.     return;
  744.     }
  745.  
  746.     mode = statbuf.st_mode & 04777;
  747.     if ((mode&06707) != 0701)
  748.     que (LEVEL1, "Wrong mode        : (0%o) on login directory; should be 711\n",
  749.             mode, ret -> pw_dir);
  750. }
  751. /* */
  752.  
  753. chkalias (name)
  754. char *name;
  755. {
  756.     int flags;
  757.     char alias[LINESIZE];
  758.  
  759.     if (aliasfetch(TRUE, name, alias, &flags) == OK) {
  760.     if ((flags & (AL_PUBLIC | AL_NOBYPASS)) == (AL_PUBLIC | AL_NOBYPASS))
  761.         que (LEVEL1, "Public alias      : '%s' (** normally not public)\n",
  762.           alias);
  763.     else if ((flags & AL_PUBLIC) == AL_PUBLIC)
  764.         que (LEVEL1, 
  765.          "Public, bypassable\n**    alias             : '%s' (** normally neither)\n",
  766.         alias);
  767.     else if ((flags & AL_NOBYPASS) == AL_NOBYPASS)
  768.         que (LEVEL6, subhdrfmt, "Alias value", alias);
  769.     else
  770.             que (LEVEL1, "Bypassable alias  : '%s' (** normally not bypassable)\n",
  771.           alias);
  772.    } else {
  773.     que (LEVEL1, "No mail alias     : for address '%s'\n", name);
  774.     }
  775.     qflush (LEVEL6);
  776. }
  777.  
  778.  
  779.  
  780. /* */
  781.  
  782. chkcmd ()
  783. {
  784.     que (LEVEL7, "\n(changing into command library...)\n");
  785.     qflush (LEVEL7);
  786.  
  787.     if (chdir (cmddfldir) < OK)
  788.     {
  789.     que (LEVEL1, probfmt, "cannot chdir", xerrstr());
  790.     return;
  791.     }
  792.  
  793.     que (LEVEL6, subhdrfmt, "Posting/submission", pathsubmit);
  794.     chkfile (pathsubmit, 04711, 04755, mmdfuid, mmdfgid, mmdflogin);
  795.     qflush (LEVEL6);
  796.  
  797.     que (LEVEL6, subhdrfmt, "Delivery management", pathdeliver);
  798.     chkfile (pathdeliver, 04711, 04755, 0, rootgid, "root");
  799.     qflush (LEVEL6);
  800.  
  801.     if (strcmp (pathdeliver, pathpkup) != 0)
  802.     {
  803.     que (LEVEL6, subhdrfmt, "P.O. Box retrieval", pathpkup);
  804.     chkfile (pathpkup, 04711, 04755, 0, rootgid, "root");
  805.     qflush (LEVEL6);
  806.     }
  807.  
  808.     que (LEVEL6, subhdrfmt, "V6Mail (for notices)",
  809.         pathmail);
  810.     chkfile (pathmail, 0711, 0755, mmdfuid, mmdfgid, mmdflogin);
  811.     qflush (LEVEL6);
  812.  
  813.     que (LEVEL6, subhdrfmt, "cleanque", "Queue garbage cleaner");
  814.     chkfile ("cleanque", 04711, 04755, 0, rootgid, "root");
  815.     qflush (LEVEL6);
  816.  
  817.     que (LEVEL6, subhdrfmt, "checkque", "Queue status checker");
  818.     chkfile ("checkque", 04711, 04755, mmdfuid, mmdfgid, mmdflogin);
  819.     qflush (LEVEL6);
  820.  
  821.     que (LEVEL6, subhdrfmt, "setlogs", "Log cleanup shellfile");
  822.     chkfile ("setlogs", 0700, 0755, mmdfuid, mmdfgid, mmdflogin);
  823.     qflush (LEVEL6);
  824. }
  825. /* */
  826.  
  827. chkchan ()
  828. {
  829.     register int ind;
  830.     register Chan *chan;
  831.  
  832.     que (LEVEL7, "\n(changing into channel directory...)\n");
  833.     qflush (LEVEL7);
  834.  
  835.     que (BACKGROUND,"\t[ Some channels, such as Local, need to be setuid ]\n");
  836.     qflush (BACKGROUND);
  837.  
  838.     if (chdir (chndfldir) < OK)
  839.     que (LEVEL1, probfmt, "cannot chdir", xerrstr());
  840.     else
  841.     {
  842.     for (ind = 0; (chan = ch_tbsrch[ind]) != (Chan *) 0; ind++)
  843.     {
  844.         que (LEVEL5, subhdrfmt, chan -> ch_show, "");
  845.         if (chan -> ch_ppath[0] == '\0')
  846.         que (LEVEL1, "No channel prog\n");
  847.         else
  848.         {
  849.         que (LEVEL6, subhdrfmt, "Channel program",
  850.                     chan -> ch_ppath);
  851.         if (stat (chan -> ch_ppath, &statbuf) < OK)
  852.             que (LEVEL1, probfmt, "Can't stat prog", xerrstr());
  853.         qflush (LEVEL6);
  854.         }
  855.         if (chan -> ch_logfile) {
  856.             chan -> ch_logfile = dupfpath(chan -> ch_logfile, logdfldir);
  857.         que (LEVEL6, subhdrfmt, "logfile", chan -> ch_logfile);
  858.         chkfile (chan -> ch_logfile, 0622, 0666, mmdfuid, mmdfgid, mmdflogin);
  859.         qflush (LEVEL6);
  860.         }
  861.         qflush (LEVEL5);
  862.     }
  863.     }
  864. }
  865. /* */
  866.  
  867. chkfile (dirptr, maxprot, minprot, owner, group, ownname)
  868. register char *dirptr;
  869. int maxprot, minprot, owner, group;
  870. char ownname[];
  871. {
  872.     register char *nptr;
  873.     char partpath[128];
  874.  
  875.     /*  verify that I have been given a real path name  */
  876.     if (!isstr(dirptr))
  877.     {
  878.     que (LEVEL1, "useless filename\n");
  879.     return (NOTOK);
  880.     }
  881.  
  882.     /*  step through the path, stopping at /'s to check the
  883.      *  directory.
  884.      */
  885.     nptr = partpath;
  886.     while ((*nptr++ = *dirptr++) != '\0')
  887.     /*  Note that this checks the NEXT char, not the one just
  888.      *  transfered.
  889.      */
  890.     if (*dirptr == '/')
  891.     {
  892.         *nptr = '\0';
  893.         if (chkpath (PARTIAL, partpath, maxprot, minprot, owner, group, ownname) != OK)
  894.         return (NOTOK);
  895.     }
  896.  
  897.     /*  At this point the entire pathname has been transfered.
  898.      *  Check it (errors here are more serious than above.)
  899.      */
  900.     if (chkpath(FINAL, partpath, maxprot, minprot, owner, group, ownname) != OK)
  901.     return (NOTOK);
  902.     return (OK);
  903. }
  904. /* */
  905.  
  906. /*  Note that a return of OK from this routine indicates only
  907.  */
  908. /*ARGSUSED*/
  909. chkpath (control, name, maxprot, minprot, owner, group, ownname)
  910. int control;
  911. char *name;
  912. int maxprot, minprot, owner, group;
  913. char *ownname;
  914. {
  915.     struct passwd *pwdptr;
  916.     static char pathdone[MAXPATH][50];
  917.     register int n;
  918.  
  919.     /*  First, must check to see if the dir is statable.
  920.      *  A failure here must return NOTOK even if this dir
  921.      *  has been checked before.
  922.      */
  923.     if (stat (name, &statbuf) < OK)
  924.     {
  925.     que (LEVEL1, probfmt, "unable to stat", xerrstr());
  926.         if (control == PARTIAL)
  927.         que (LEVEL1, "Unable to proceed checking this path.\n");
  928.     return (NOTOK);
  929.     }
  930.  
  931.     /*  If this path has already been checked, then don't
  932.      *  do it again.  The repeated error msgs are annoying.
  933.      */
  934.     for (n = 0;  ((n < MAXPATH) && (pathdone[n][0] != '\0'));  n++)
  935.     if (strcmp (name, pathdone[n]) == 0)
  936.         return (OK);
  937.  
  938.     /*  save this name as one that has been checked  */
  939.     if (n < MAXPATH)
  940.     (void) strcpy (pathdone[n], name);
  941.  
  942.     /*  verify that the owner is correct  */
  943.     if (statbuf.st_uid != owner)
  944.     {
  945.     if ((pwdptr = getpwuid (statbuf.st_uid)) != NULL)
  946.     {
  947.         if (control == FINAL)
  948.         que (LEVEL1, "Wrong owner       : (%s) for '%s'; should be %s\n",
  949.             pwdptr -> pw_name, name, ownname);
  950.         else
  951.         que (LEVEL6_5, "\t[ Wrong owner   : (%s) for '%s'; should be %s ]\n",
  952.             pwdptr -> pw_name, name, ownname);
  953.     }
  954.     else
  955.     {
  956.         if (control == FINAL)
  957.         que (LEVEL1, "Wrong owner      : (uid %d) for '%s'; should be %s\n",
  958.                 statbuf.st_uid, name, ownname);
  959.         else
  960.         que (LEVEL6_5, "\t[ Wrong owner  : (uid %d) for '%s'; should be %s ]\n",
  961.                 statbuf.st_uid, name, ownname);
  962.     }
  963.     qflush (LEVEL6_5);
  964.     }
  965.  
  966.     /* 
  967.      *  Ingore bits that are site choice and not critical to operation.
  968.      */
  969.     if (control == PARTIAL) {
  970.         minprot |= 0111;
  971.         maxprot |= 0111;
  972.     }
  973.     statbuf.st_mode &= 06707;
  974.     minprot &= 06707;
  975.     maxprot &= 06707;
  976.     if ((statbuf.st_mode&(~minprot)) ||     /* Any extra bit on? */
  977.         (statbuf.st_mode&maxprot) != maxprot)    /* Any bits missing? */
  978.     {
  979.     if (control == FINAL)
  980.         que (LEVEL1, "Wrong mode        : (0%o) for '%s'; should be (0%o to 0%o)\n",
  981.             statbuf.st_mode, name, maxprot, minprot);
  982.     else
  983.         que (LEVEL6_5, "\t[ Wrong mode    : (0%o) for '%s'; should be (0%o to 0%o) ]\n",
  984.             statbuf.st_mode, name, maxprot, minprot);
  985.     qflush (LEVEL6_5);
  986.     }
  987.     return (OK);
  988. }
  989.  
  990. chktai ()
  991. {
  992.     if (mmtailor != (char *) 0)
  993.     {
  994.     if (stat (mmtailor, &statbuf) < OK)
  995.     {
  996.         que (LEVEL1, "No tailor file   : %s", mmtailor);
  997.         endit (NOTOK);
  998.     }
  999.     else
  1000.         que (LEVEL4, hdrfmt, "Tailor file", mmtailor);
  1001.     qflush (LEVEL4);
  1002.     }
  1003. }
  1004. /* */
  1005.  
  1006. int prtmax;
  1007. struct prtque prtque[QUESIZ];
  1008.  
  1009. qflush (control)
  1010. int control;
  1011. {
  1012.     register int index, prtany;
  1013.  
  1014.     /*  determine if any of the queue should be output */
  1015.     for (prtany = index = 0;  index < prtmax;  index++)
  1016.     if (prtque[index].q_level <= verbosity)
  1017.     {
  1018.         prtany = 1;
  1019.         break;
  1020.     }
  1021.  
  1022.     if (prtany != 0)        /*  go through and print appropriate lines  */
  1023.     {
  1024.     for (index = 0;  index < prtmax;  index++)
  1025.         printf ("%s", prtque[index].q_text);
  1026.     prtmax = 0;            /* start over */
  1027.     }
  1028.     else
  1029.     {
  1030.     for (index = 0;     /* remove excess only */
  1031.         (index < prtmax) && (prtque[index].q_level < control);
  1032.         index++)
  1033.         ;
  1034.     prtmax = index;
  1035.     }
  1036.     return;
  1037. }
  1038.  
  1039. /*VARARGS1*/
  1040. que (control, msg, arga, argb, argc, argd)
  1041. int control;
  1042. char *msg, *arga, *argb, *argc, *argd;
  1043. {
  1044.     char tmp[128];
  1045.  
  1046.     if (prtmax < (QUESIZ-1))
  1047.     format (prtque[prtmax].q_text, control, msg, arga, argb, argc, argd);
  1048.     else
  1049.     {
  1050.     qflush (LEVEL0);
  1051.     printf ("Recompile this program with larger QUESIZ.\n");
  1052.     printf ("Queue overflow on:\n  ");
  1053.     format (tmp, control, msg, arga, argb, argc, argd);
  1054.     printf (tmp);
  1055.     exit (NOTOK);
  1056.     }
  1057.     prtque[prtmax].q_level = control & ~PERROR;
  1058.     if (prtque[prtmax].q_level <= verbosity)
  1059.     qflush (prtque[prtmax++].q_level);
  1060.     else
  1061.     prtmax++;
  1062.     return;
  1063. }
  1064. /* */
  1065.  
  1066. /*VARARGS2*/
  1067. format (buff, control, msg, arga, argb, argc, argd)
  1068. char buff[];
  1069. int control;
  1070. char *msg, *arga, *argb, *argc, *argd;
  1071. {
  1072.     register int n;
  1073.  
  1074.     switch (control&~PERROR)
  1075.     {
  1076.     case LEVEL1:
  1077.         (void) strncpy (buff, "**    ", 6);
  1078.         n = 6;
  1079.         break;
  1080.  
  1081.     default:
  1082.         n = 0;
  1083.     }
  1084.  
  1085.     (void) sprintf (&buff[n], msg, arga, argb, argc, argd);
  1086.  
  1087.     if ((control & PERROR) && (errno > 0)) {
  1088.         n = strlen(buff);
  1089.     (void) sprintf(&buff[n], " (%s)\n", xerrstr());
  1090.     }
  1091.  
  1092.     return;
  1093. }
  1094.  
  1095. char *
  1096. xerrstr()
  1097. {
  1098.     static char buff[64];
  1099.  
  1100.     if (errno > sys_nerr || errno < 0)
  1101.     (void) sprintf (buff, "Errno %d", errno);
  1102.     else
  1103.     (void) strcpy(buff, sys_errlist[errno]);
  1104.     return (buff);
  1105. }
  1106. /* */
  1107. /*ARGSUSED*/
  1108. post_tai (argc, argv)           /* let user know about unknowns tailor info */
  1109.     int argc;
  1110.     char *argv[];
  1111. {
  1112.     char errline[LINESIZE];
  1113.  
  1114.     arg2vstr (0, sizeof errline, errline, argv);
  1115.     if (tai_eptr == (char *) 0)
  1116.     {
  1117.     if (errno == 0)
  1118.         que (LEVEL1, "Unknown tailor    : '%s'\n", errline);
  1119.     else
  1120.         que (LEVEL1, "Tailor error      : '%s'\n", errline);
  1121.     }
  1122.     else                        /* problem with subfield, not field name */
  1123.     que (LEVEL1, "Tailor error      : with '%s' in line: '%s'\n",
  1124.             tai_eptr, errline);
  1125.  
  1126.     if (errno > 0 && errno <= sys_nerr)
  1127.     que (LEVEL1, "                  : [ %s ]\n", sys_errlist[errno]);
  1128.  
  1129.     errflg = TRUE;
  1130.  
  1131.     return (YES);   /* we like everthing */
  1132. }
  1133.  
  1134. endit (type)
  1135.     int type;
  1136. {
  1137.     qflush (LEVEL0);
  1138.     (void) fflush (stdout);
  1139.     exit (type);
  1140. }
  1141.